let oldArrayProto = Array.prototype

export let newArrayProto = Object.create(oldArrayProto)

// defineProperty的缺陷，数组index变化不能被拦截
// 需要重写的数组方法
let methods = [
  'push',
  'pop',
  'shift',
  'unshift',
  'reverse',
  'sort',
  'splice'
]

methods.forEach(method => {
  let original = oldArrayProto[method]

  // 在原本的原型链中加了一层, 为了拦截push, pop....等改变数组的方法引发响应式变化
  // 注意.不能直接在newArrayProto.__proto__上定义方法,会死循环,因为newArrayProto.__proto__就是数组构造方法的prototype
  // 而基于这次重新定义,内部又调用了此方法会死循环,
  // newArrayProto.__proto__[method] = function (...args) {
  newArrayProto[method] = function (...args) {
  // 调用这些方法时，this就是这个数组，之前在这个数组上挂载了一个属性__ob__，即观察者实例
    let ob = this.__ob__
    // 需要插入的元素
    let inserted
    switch (method) {
      case 'push':
      case 'unshift': {
        inserted = args
        break;
      }
      case 'splice': {
        inserted = args.slice(2)
        break;
      }
    }
    // 前面将ob挂载到对象/数组的状态上，并在观察者构造函数创建dep实例，
    // 就是为了直接通过数组/对象本身直接拿到ob，dep，进而基于dep的notify方法进行更新
    ob.dep.notify()
    inserted && ob.observeArray(inserted)
    const result = original.call(this, ...args)
    return result
  }
})